package cn.com.dcsgo.service.impl;

import cn.com.dcsgo.constant.EsConstant;
import cn.com.dcsgo.dto.PageDTO;
import cn.com.dcsgo.dto.ProdSearchDTO;
import cn.com.dcsgo.exception.BusinessException;
import cn.com.dcsgo.model.ProdEs;
import cn.com.dcsgo.service.SearchService;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Highlight;
import co.elastic.clients.elasticsearch.core.search.HighlightField;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * SearchServiceImpl
 *
 * @author Dcsgo
 * @since 2025/11/3 13:55
 */
@Slf4j
@Service
public class SearchServiceImpl implements SearchService {
    @Resource
    private ElasticsearchClient elasticsearchClient;


    @Override
    public Page<ProdEs> getProdListByTagId(PageDTO pageDTO, Long tagId) {
        Integer current = pageDTO.getCurrent();
        Integer size = pageDTO.getSize();
        Page<ProdEs> result = new Page<>(current, size);
        MatchQuery tagIdMathQuery = MatchQuery.of(math -> math.field("tagList").query(tagId));
        SearchResponse<ProdEs> response;
        try {
            response = elasticsearchClient.search(builder ->
                            builder.index(EsConstant.PROD_ES_INDEX)//索引
                                    .query(tagIdMathQuery._toQuery())//查询条件
                                    .from((current - 1) * size)//偏移量
                                    .size(size)//每页条数
                    , ProdEs.class);
            HitsMetadata<ProdEs> hits = response.hits();
            // 取出总条数
            long totalCount = hits.total() == null ? 0 : hits.total().value();
            result.setTotal(totalCount);
            List<Hit<ProdEs>> hitList = hits.hits();
            ArrayList<ProdEs> prodEsList = new ArrayList<>(hitList.size());
            for (Hit<ProdEs> prodEsHit : hitList) {
                prodEsList.add(prodEsHit.source());
            }
            result.setRecords(prodEsList);
        } catch (IOException e) {
            log.error("通过活动ID查询商品信息失败，失败原因：{}", e.getMessage());
            throw new RuntimeException(e);
        }
        return result;
    }

    @Override
    public Page<ProdEs> searchProd(PageDTO pageDTO, ProdSearchDTO prodSearchDTO) {
        Integer current = pageDTO.getCurrent();
        Integer size = pageDTO.getSize();
        String keyword = prodSearchDTO.getProdName();
        Page<ProdEs> result = new Page<>(current, size);
        //构造商品名、简介内容的多条件查询
        Query multiMatchQuery = QueryBuilders.multiMatch(m -> m.fields("prodName", "brief").query(keyword));
        //排序
        SortOptions sortOptions = getSortOptions(prodSearchDTO);
        //关键词匹配高亮
        Highlight.Builder hb = new Highlight.Builder();
        HighlightField hf = new HighlightField.Builder().build();
        hb.preTags("<span style='color: red;'>").postTags("</span>");
        hb.fields("prodName", hf);
        hb.fields("brief", hf);
        //查询
        SearchResponse<ProdEs> response;
        try {
            response = elasticsearchClient.search(builder ->
                            builder.index(EsConstant.PROD_ES_INDEX)//索引
                                    .query(multiMatchQuery)//查询条件
                                    .from((current - 1) * size)//偏移量
                                    .size(size)//每页条数
                                    .highlight(hb.build())//高亮
                                    .sort(sortOptions)
                    , ProdEs.class);
            HitsMetadata<ProdEs> hits = response.hits();
            // 取出总条数
            long totalCount = hits.total() == null ? 0 : hits.total().value();
            result.setTotal(totalCount);
            List<Hit<ProdEs>> hitList = hits.hits();

            ArrayList<ProdEs> prodEsList = new ArrayList<>(hitList.size());
            for (Hit<ProdEs> prodEsHit : hitList) {
                ProdEs prodEs = prodEsHit.source();
                //处理高亮
                Map<String, List<String>> highlightMap = prodEsHit.highlight();
                if (highlightMap.containsKey("prodName")) {
                    List<String> name = highlightMap.get("prodName");
                    String highlightName = name.get(0);
                    //替换prodEs里面的商品名称
                    if (prodEs != null) {
                        prodEs.setProdName(highlightName);
                    }
                }
                prodEsList.add(prodEs);
            }
            result.setRecords(prodEsList);
        } catch (IOException e) {
            log.error("搜索商品失败，失败原因：{}", e.getMessage());
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * 获取排序方式
     *
     * @param prodSearchDTO 搜索商品请求参数
     * @return 排序方式
     */
    private SortOptions getSortOptions(ProdSearchDTO prodSearchDTO) {
        Integer sort = prodSearchDTO.getSort();
        Integer sortType = prodSearchDTO.getSortType();
        SortOrder order = sortType.equals(0) ? SortOrder.Asc : SortOrder.Desc;
        return switch (sort) {
            case 0 -> //综合--按好评率
                    SortOptions.of(
                            builder -> builder.field(field -> field.field("praiseNumber").order(order))
                    );
            case 1 -> //销量
                    SortOptions.of(
                            builder -> builder.field(field -> field.field("soldNum").order(order))
                    );
            case 2 -> //价格
                    SortOptions.of(
                            builder -> builder.field(field -> field.field("price").order(order))
                    );
            default -> throw new BusinessException("排序类型不存在");
        };
    }
}
